const Service = require('egg').Service
const _ = require('lodash')
const cache = require('memory-cache')
const ms = require('ms')

class BaseServicer extends Service {
  constructor(...args) {
    super(...args)

    this.createFind()
  }

  // 默认模型
  get Model() { }

  // 默认查询条件
  get findOptions() { }

  /**
   * 创建查询函数
   */
  createFind() {
    const { ctx } = this
    const { helper } = ctx

      ;['find', 'findOne', 'findPage'].forEach((action) => {
        this[action] = async (...args) => {
          let filter = {}
          let options = {}

          // 兼容老项目写法，后期废弃
          if (args[0] && args[0].where) {
            filter = args[0].where
            options = {
              ...args[0],
            }
          } else {
            filter = args[0]
            if (typeof args[1] == 'function') {
              options = {
                fn: args[1],
              }
            } else {
              options = {
                ...args[1],
              }
            }
          }

          options = {
            ...this.findOptions,
            ...options,
          }

          filter = {
            ...(this.where || this.filter),
            ...(options.where || options.filter),
            ...filter,
          }

          const { cacheName, fn } = options

          if (cacheName) {
            const cacheData = cache.get(cacheName)
            if (cacheData) {
              // console.log('[service] 读取缓存', cacheName)
              return cacheData
            }
          }

          // 去掉过滤器中undefined的字段
          Object.keys(filter).forEach((key) => {
            if (filter[key] == undefined) {
              delete filter[key]
            }
          })

          let find
          if (action == 'findPage') {
            find = this.Model[action](filter, options)
          } else {
            find = this.Model[action](filter)

            delete options.where // where已经合并到filter，不再通过链式语法执行
            Object.keys(options).map((action) => {
              if (find[action]) find = find[action](options[action])
            })

            if (fn) fn = fn(find)
          }

          const data = await find
          const afterfnName = _.camelCase(`after_${action}`)
          const newData = await this[afterfnName](data)
          const returnData = newData ? newData : data

          if (cacheName) {
            const cacheTime = options.cacheTime || '60s'
            cache.put(cacheName, returnData, ms(cacheTime))
            console.log('[service 设置缓存]', cacheName)
          }

          return returnData
        }
      })
  }

  // find查询后
  async afterFind(docs) {
    const { ctx } = this
    const { helper } = ctx

    if (this.formatData && docs.length) {
      let newData = []
      await helper.queue(docs, async (doc, index) => {
        if (doc.toJSON) doc = doc.toJSON()
        const newDoc = await this.formatData(doc, 'find')
        newData[index] = newDoc ? newDoc : doc
      })

      return newData
    }

    return docs
  }

  async afterFindOne(doc) {
    if (this.formatData && doc) {
      doc = doc.toJSON()
      const newDoc = await this.formatData(doc, 'findOne')
      if (newDoc) doc = newDoc
    }

    return doc
  }

  async afterFindPage(data) {
    const { ctx } = this
    const { helper } = ctx

    if (this.formatData && data.list.length) {
      let newList = []
      await helper.queue(data.list, async (doc, index) => {
        if (doc.toJSON) doc = doc.toJSON()
        const newDoc = await this.formatData(doc, 'findPage')
        newList[index] = newDoc ? newDoc : doc
      })

      data.list = newList
    }

    return data
  }
}

module.exports = BaseServicer
